// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//

#pragma once

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_NONSTDC_NO_DEPRECATE

#ifdef _DEBUG
	#define _CRTDBG_MAP_ALLOC 
	#include <stdlib.h> 
	#include <crtdbg.h>
#else
	#include <stdlib.h> 
#endif

#ifdef WIN32
    #include <SDKDDKVer.h>
    #define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers
    // Windows Header Files:
    #include <windows.h>
    #include <process.h>
#else
	#include <pthread.h>
    #include <unistd.h>
    #include <fcntl.h>
#endif

// TODO: reference additional headers your program requires here
//#include <tchar.h>

#include <string.h>
#include <errno.h>
#include <signal.h>

#ifndef WIN32
	#include <netinet/in.h>
	#include <arpa/inet.h>
	#include <sys/socket.h>
#else
	#include <winsock2.h>
#endif

#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <event2/event.h>
#include <event2/thread.h>

#include <event2/bufferevent_ssl.h>
#include <openssl/err.h>
#include <openssl/ssl.h>

#include "list.h"
#include "bmtp2.h"

#ifdef WIN32

#define bmtp_errno                  GetLastError()
#define bmtp_set_errno(err)         SetLastError(err)
#define bmtp_socket_errno           WSAGetLastError()
#define bmtp_set_socket_errno(err)  WSASetLastError(err)
#define bmtp_fd_t                   HANDLE
#define bmtp_err_t                  DWORD

#define ssize_t long
#define snprintf _snprintf

#define BMTP_EAGAIN                 WSAEWOULDBLOCK
#define BMTP_ENOPROTOOPT            WSAENOPROTOOPT

#else

#define bmtp_errno                  errno
#define bmtp_set_errno(err)         errno = err
#define bmtp_socket_errno           errno
#define bmtp_set_socket_errno(err)  errno = err
#define bmtp_fd_t                   int
#define bmtp_err_t                  int

#if (__hpux__)
#define BMTP_EAGAIN        EWOULDBLOCK
#else
#define BMTP_EAGAIN        EAGAIN
#endif
#define BMTP_ENOPROTOOPT   ENOPROTOOPT

#endif

enum {
    STATE_START = 0,
    STATE_KEY,
    STATE_SPECIAL_HEADER,
    STATE_KEY_EXT1,
    STATE_KEY_EXT2,
    STATE_KEY_EXT3,
    STATE_KEY_EXT4,
    STATE_VALUE,
    STATE_VALUE_BOOL,
    STATE_VALUE_VARINT,
    STATE_VALUE_VARINT_EXT1,
    STATE_VALUE_VARINT_EXT2,
    STATE_VALUE_VARINT_EXT3,
    STATE_VALUE_VARINT_EXT4,
    STATE_VALUE_VARINT_EXT5,
    STATE_VALUE_VARINT_EXT6,
    STATE_VALUE_VARINT_EXT7,
    STATE_VALUE_VARINT_EXT8,
    STATE_VALUE_VARINT_EXT9,
    STATE_VALUE_STRING,
    STATE_VALUE_64BIT,
    STATE_PAYLOAD_LENGTH,
    STATE_PAYLOAD_LENGTH_EXT1,
    STATE_PAYLOAD_LENGTH_EXT2,
    STATE_PAYLOAD_LENGTH_EXT3,
    STATE_PAYLOAD_LENGTH_EXT4,
    STATE_PAYLOAD,
    STATE_END
};

struct bmtp_param_list {
    list_t head;
    
    unsigned int key;
    unsigned int key_type:3;
    struct {
        unsigned char *s;
        unsigned long long int l;
    } value;
};

struct bmtp_package {
    list_t head;

    unsigned int op_code;
    unsigned int op_type:3;
    struct {
        unsigned char *s;
        unsigned long long int l;
    } op_value;
    
    struct bmtp_param_list param;
    unsigned int param_len;
    
    unsigned long long int stream_id;
    
    unsigned int payload_length;
    unsigned char *payload;
    
    unsigned int  send_offset;
    unsigned int  send_buf_len;
    unsigned char *send_buf;
};

struct bmtp_context {
    evutil_socket_t fd;
    struct event_base *base;
    struct event *event_write;
    struct event *event_read;
    struct sockaddr_in server_addr;
    
    unsigned int  secure;
    SSL *ssl;
    
    unsigned char *token;
    unsigned int  token_len;

    unsigned int  recv_length;
    unsigned int  recv_offset;
    unsigned char *recv_buf;
    
    unsigned int  state;

    // 指令
    unsigned int op_code;
    unsigned int op_type:3;
    struct {
        unsigned char *s;
        unsigned long long int l;
    } op_value;
    
    unsigned int payload_length;
    unsigned char *payload;
    
    //unsigned long long int stream_id;

    struct bmtp_package send_queue;
    struct bmtp_package ack_queue;

    void( *on_open )( BMTP* );
    void( *on_close )( BMTP* );
    void( *on_error )( BMTP*, int );
    
    void( *on_pub )( BMTP*, BMTP_MSG* );
    void( *on_ack )( BMTP*, BMTP_PACKAGE*, int );
    
    bmtp_fd_t  log_fd;
    char *log_buf;
    unsigned int log_buf_len;

    // 用于 send_queue 加锁
    // ack_queue 不需要加锁，因为只有单线程访问
#ifdef WIN32
    CRITICAL_SECTION cs;
#else
    pthread_mutex_t cs;
#endif
};
